package util

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-admin-team/go-admin-core/sdk/config"
	"github.com/go-admin-team/go-admin-core/sdk/pkg"
	"github.com/go-admin-team/go-admin-core/sdk/pkg/utils"
	"github.com/google/uuid"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"tuowei.com/app/admin/service/dto"
	"tuowei.com/common/file_store"
	Beans "tuowei.com/pkg/sing/beans"
	"tuowei.com/pkg/sing/http_utils"
	"tuowei.com/pkg/sing/sign_service"
	Tools "tuowei.com/pkg/sing/utils"
	"tuowei.com/pkg/xlog"
)

type FileResponse struct {
	Size     int64  `json:"size"`
	Path     string `json:"path"`
	FullPath string `json:"full_path"`
	Name     string `json:"name"`
	Type     string `json:"type"`
}

const path = "./static/uploadfile/"
const url = "http://image.twzxjy.com"

func UploadBase64(ctx *gin.Context, fileBase64Str string) (FileResponse, error) {
	fileResponse := FileResponse{}
	file2list := strings.Split(fileBase64Str, ",")
	if len(file2list) != 2 {
		return fileResponse, errors.New("无效图片格式")
	}
	//data:image/png;base64
	mime := strings.Split(file2list[0], ";")
	if len(mime) != 2 || mime[1] != "base64" {
		return fileResponse, errors.New("不是base64图片格式1")
	}

	mime1 := strings.Split(mime[0], ":")
	if len(mime1) != 2 || mime1[0] != "data" {
		return fileResponse, errors.New("不是base64图片格式2")
	}
	mime2 := strings.Split(mime1[1], "/")

	if len(mime2) != 2 || mime2[0] != "image" {
		return fileResponse, errors.New("不是base64图片格式3")
	}
	suffix := "." + mime2[1]
	ddd, _ := base64.StdEncoding.DecodeString(file2list[1])
	guid := uuid.New().String()
	fileName := guid + suffix
	//err := utils.IsNotExistMkDir(path)
	//if err != nil {
	//	return fileResponse, errors.New("初始化文件路径失败")
	//}
	base64File := path + fileName
	_ = ioutil.WriteFile(base64File, ddd, 0666)
	typeStr := strings.Replace(strings.Replace(file2list[0], "data:", "", -1), ";base64", "", -1)
	urlPrefix := fmt.Sprintf("http://%s/", ctx.Request.Host)

	fileResponse = FileResponse{
		//Size:     pkg.GetFileSize(base64File),
		Path:     base64File,
		FullPath: urlPrefix + base64File,
		Name:     "",
		Type:     typeStr,
	}
	_model := ""
	if config.ApplicationConfig.Mode == "dev" {
		_model = "dev"
	} else if config.ApplicationConfig.Mode == "test" {
		_model = "test"
	} else if config.ApplicationConfig.Mode == "prod" {
		_model = "prod"
	} else {
		_model = "test"
	}
	nowTime := time.Now().Format("2006/01/02")
	dirPath := path + _model + "/" + nowTime + "/"
	err := thirdUpload(fileName, base64File, dirPath)
	if err != nil {
		return fileResponse, errors.New("上传第三方失败")
	}
	fileResponse.Path = url + dirPath + fileName
	fileResponse.FullPath = url + dirPath + fileName
	return fileResponse, nil
}
func Upload(ctx *gin.Context, filename string) (FileResponse, error) {
	files, err := ctx.FormFile(filename)
	var fileResponse FileResponse
	if err != nil {
		return fileResponse, errors.New(filename + "不存在")
	}
	guid := uuid.New().String()

	fileName := guid + utils.GetExt(files.Filename)
	err = utils.IsNotExistMkDir(path)
	if err != nil {
		return fileResponse, err
	}
	_model := ""
	if config.ApplicationConfig.Mode == "dev" {
		_model = "dev"
	} else if config.ApplicationConfig.Mode == "test" {
		_model = "test"
	} else if config.ApplicationConfig.Mode == "prod" {
		_model = "prod"
	} else {
		_model = "test"
	}
	nowTime := time.Now().Format("2006/01/02")

	singleFile, err := createDateDir(path, _model+"/"+nowTime, fileName)
	if err != nil {
		return fileResponse, err
	}
	err = ctx.SaveUploadedFile(files, singleFile)
	if err != nil {
		return fileResponse, err
	}
	defer func() {
		// 删除本地文件
		err = os.Remove(singleFile)
	}()
	fileType, _ := utils.GetType(singleFile)
	urlPrefix := fmt.Sprintf("http://%s/", ctx.Request.Host)

	fileResponse = FileResponse{
		Size:     pkg.GetFileSize(singleFile),
		Path:     singleFile,
		FullPath: urlPrefix + singleFile,
		Name:     files.Filename,
		Type:     fileType,
	}
	dirPath := path + _model + "/" + nowTime + "/"
	xlog.Error("开始oss上传 :", time.Now().Format("2006-01-01 15:04:05"))

	err = thirdUpload(fileName, singleFile, dirPath)
	xlog.Error("结束oss上传 :", time.Now().Format("2006-01-01 15:04:05"))

	if err != nil {
		return fileResponse, err
	}
	fileResponse.Path = url + dirPath + fileName
	fileResponse.FullPath = url + dirPath + fileName
	return fileResponse, nil
}

//basePath是固定目录路径
func createDateDir(basePath string, newDir string, fileName string) (filePath string, err error) {

	folderPath := filepath.Join(basePath, newDir)
	if _, err := os.Stat(folderPath); os.IsNotExist(err) {
		// 必须分成两步
		// 先创建文件夹
		err := os.MkdirAll(folderPath, 0777)
		xlog.Error(err)
		// 再修改权限
		os.Chmod(folderPath, 0777)
	}
	return folderPath + "/" + fileName, nil
}

func thirdUpload(name string, filepath string, path string) error {

	path = strings.TrimLeft(path, "/")
	return ossUpload(path+name, filepath)
}
func ossUpload(name string, path string) error {
	oss := file_store.ALiYunOSS{}
	return oss.UpLoad(name, path)
}

// UploadESign 上传到e电签
func UploadESign(ctx *gin.Context, filename string) (Beans.UploadFileRsp, error) {
	response := Beans.UploadFileRsp{}
	files, err := ctx.FormFile(filename)
	//var fileResponse FileResponse
	if err != nil {
		return response, errors.New(filename + "不存在")
	}
	guid := uuid.New().String()

	fileName := guid + utils.GetExt(files.Filename)
	err = utils.IsNotExistMkDir(path)
	if err != nil {
		return response, err
	}
	nowTime := time.Now().Format("2006/01/02")

	singleFile, err := createDateDir(path, "e_sign"+"/"+nowTime, fileName)
	if err != nil {
		return response, err
	}
	err = ctx.SaveUploadedFile(files, singleFile)
	sign_service.EsignInitService()
	if err != nil {
		return response, err
	}
	defer func() {
		// 删除本地文件
		err = os.Remove(singleFile)
	}()
	f, err := os.Open(singleFile)
	if err != nil {
		xlog.Error(err)
		return response, err
	}
	info, _ := f.Stat()
	buf := make([]byte, 512)
	f.Read(buf)
	contentType := http.DetectContentType(buf)
	contentMd5, _ := Tools.CountFileMd5(singleFile)
	uploadReq := Beans.UploadFileReq{
		ContentMd5:    contentMd5,
		ContentType:   contentType,
		FileName:      info.Name(),
		FileSize:      info.Size(),
		ConvertToPDF:  false,
		ConvertToHTML: false,
	}
	jsonStrBt, _ := json.Marshal(uploadReq)
	bt, code := http_utils.SendCommHttp("/v3/files/file-upload-url", string(jsonStrBt), http.MethodPost)
	if code != http.StatusOK {
		return response, errors.New("电签三方上传失败")
	}
	json.Unmarshal(bt, &response)
	if response.Code != 0 {
		return response, errors.New(response.Message)
	}
	// 开始真正上传文件
	realResponse := Beans.RealUploadFileRsp{}
	r := http_utils.UpLoadFile(response.Data.FileUploadUrl, singleFile, contentMd5, contentType)
	json.Unmarshal([]byte(r), &realResponse)
	if realResponse.ErrCode != 0 {
		return response, errors.New(realResponse.Msg)
	}
	duration := 20
	timer := time.NewTimer(time.Second * time.Duration(duration))
	defer timer.Stop()
LOOP:
	for {
		select {
		case <-timer.C:
			return response, errors.New(fmt.Sprintf("超过%d秒e签还没有转换完文档格式", duration))
		// 超时都还没有获得结果，直接返回错误
		default:
			// 检测文件状态
			statusRsp, err := http_utils.CheckFileStatus(response.Data.FileId)
			if err != nil {
				xlog.Error(err)
			}
			// 转换完成之后才开始跳出循环，进行下一步
			if statusRsp.Data.FileStatus == 2 || statusRsp.Data.FileStatus == 5 {
				break LOOP
			}
		}
	}
	// 上传之后调获制作合同模板页面
	req2 := dto.GetCreateTemplateUrl{}
	req2.DocTemplateName = files.Filename
	req2.FileId = response.Data.FileId
	req2.DocTemplateType = 0
	req2.RedirectUrl = ""
	var jsonStr string
	if data, err := json.Marshal(req2); err == nil {
		jsonStr = string(data)
	}
	bts, httpStatus := http_utils.SendCommHttp("/v3/doc-templates/doc-template-create-url", jsonStr, http.MethodPost)
	if httpStatus != http.StatusOK {
		return response, errors.New("调获制作合同模板页面失败，状态码:" + strconv.Itoa(httpStatus))
	}
	rsp := Beans.GetCreateTemplateUrlRsp{}
	json.Unmarshal(bts, &rsp)
	if rsp.Code != 0 {
		return response, errors.New(rsp.Message)
	}
	response.Data.FileName = files.Filename
	response.Data.TemplateId = rsp.Data.DocTemplateId
	response.Data.DocTemplateCreateUrl = rsp.Data.DocTemplateCreateUrl
	return response, nil
}
